﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IsmsExplorer.Infrastructure.DomainBase;
using IsmsExplorer.Model.Documents;
using IsmsExplorer.Model.Iso27001;
using System.Diagnostics;

namespace IsmsExplorer.Model.RiskRegister {
    public class Treatment : EntityBase, ICloneable {
        private int _projectID;
        private Threat _threat;
        private string _reference;
        private int _v;
        private int _l;
        private int _i;
        // The ISO 27001 Controls (and their associated documents) applied with this treatment.
        // The map allows for easier access of (control, associated-documents) based on control ID.
        private Dictionary<int, Iso27001ControlDocumentation> _idToControlDocs = new Dictionary<int, Iso27001ControlDocumentation>();

        public Treatment(int id, Threat threat)
            : base(id) {
            _threat = threat;
        }
        public Treatment()
            : this(0, null) {
        }

        public IEnumerable<Iso27001ControlDocumentation> ControlDocuments {
            get {
                return _idToControlDocs.Values.AsEnumerable();
            }
        }

        /// <summary>
        /// Gets or sets the corresponding Iso27001ControlDocumentation object associated with this Treatment 
        /// for the specified control. 
        /// NOTE: If setting a value of null for a control ID, the Iso27001ControlDocumentation corresponding to
        /// the supplied control ID is removed.
        /// </summary>
        /// <param name="controlID">the ID of the control</param>
        /// <returns>the Iso27001ControlDocumentation object corresponding to the control ID or null if not one is 
        /// associated with this Treatment</returns>
        public Iso27001ControlDocumentation this[int controlID] {
            get {
                Iso27001ControlDocumentation control;
                if (_idToControlDocs.TryGetValue(controlID, out control)) {
                    return control;
                } else {
                    return null;
                }
            }
            set {
                if (_idToControlDocs.ContainsKey(controlID)) {
                    if (value != null) {
                        _idToControlDocs[controlID] = value;
                    } else {
                        // null removes any documentation related to the control of the specified ID.
                        _idToControlDocs.Remove(controlID);
                    }
                } else {
                    // It's a new control doc, add it!
                    AddControlDocument(value);
                }
            }
        }

        protected void AddControlDocument(Iso27001ControlDocumentation doc) {
            if (doc != null) {
                _idToControlDocs.Add(doc.IsoControl.ID, doc);
            }
        }

        protected void RemoveControlDocument(Iso27001ControlDocumentation doc) {
            if (doc != null) {
                _idToControlDocs.Remove(doc.IsoControl.ID);
            }
        }

        public IList<Iso27001Control> IsoControlList {
            get {
                List<Iso27001Control> list = new List<Iso27001Control>();
                foreach (var o in ControlDocuments) {
                    Debug.Assert(o.IsoControl != null);
                    list.Add(o.IsoControl);
                }
                return list;
            }
        }

        public int ManagedRiskExposure {
            get { return V + L + I; }
        }

        public int I {
            get { return _i; }
            set { _i = value; }
        }

        public int L {
            get { return _l; }
            set { _l = value; }
        }

        public int V {
            get { return _v; }
            set { _v = value; }
        }

        public string Reference {
            get { return _reference; }
            set { _reference = value; }
        }

        public int ProjectID {
            get { return _projectID; }
            set { _projectID = value; }
        }

        public Threat Threat {
            get { return _threat; }
            set {
                _threat = value;
                if (_threat != null && _threat.Treatment != this) {
                    _threat.Treatment = this;
                }
            }
        }

        /// <summary>
        /// Copies the Treatment content.
        /// NOTE: this is not a 100% deep copy as the IsoControlDocuments are NOT being copied!
        ///       Also, the Threat object is not cloned to avoid infinite loop (Threat clones Treatment).
        /// </summary>
        /// <returns></returns>
        public object Clone() {
            Treatment o = new Treatment {
                I = this.I,
                ID = this.ID,
                L = this.L,
                ProjectID = this.ProjectID,
                Reference = this.Reference,
                Threat = this.Threat,
                V = this.V

            };
            // Copy and IsoControlDocuments.
            foreach (var controlID in _idToControlDocs.Keys) {
                o[controlID] = _idToControlDocs[controlID];
            }
            // Return object.
            return o;
        }

    } // end public class Treatment : EntityBase
}
